公告

👇欢迎大家关注公众号&私信交流👇

Skip to content

Flutter 实现 Widget 截图并保存到本地 ​

在 Flutter 中,将 Widget 转换为图片并保存或分享是一项常见需求。无论是为了保存当前屏幕,还是分享某个特定 UI 部分的截图,这些功能都可以通过 RepaintBoundary 实现。本文将详细介绍如何在 Flutter 中实现 Widget 截图并将图片保存到本地。

实现原理 ​

RepaintBoundary 是 Flutter 提供的一个组件,它可以将某个 Widget 包裹在一个独立的绘制区域内,并允许你将该区域渲染为图片。核心步骤如下:

  1. 用 RepaintBoundary 包裹需要截图的 Widget。
  2. 使用 GlobalKey 获取 RepaintBoundary 的上下文。
  3. 调用 toImage() 方法将 Widget 转换为图片。
  4. 将图片转换为 Uint8List 格式,并保存到本地或分享。

具体实现步骤 ​

包裹 Widget 并使用 GlobalKey ​

首先,将需要截图的部分用 RepaintBoundary 包裹,并通过 GlobalKey 获取对应的上下文。

dart
RepaintBoundary(
  key: _globalKey,
  child: Container(
    color: Colors.blueAccent,
    padding: const EdgeInsets.all(16.0),
    child: const Text(
      '这是一个可以截图的 Widget',
      style: TextStyle(color: Colors.white, fontSize: 24.0),
    ),
  ),
)

将 Widget 转换为图片 ​

使用 GlobalKey 获取 RepaintBoundary 的 RenderObject,然后将其渲染为图片,并转换为 Uint8List,以便后续的保存或分享操作。

dart
/// 创建图片
  Future<Uint8List?> capturePng() async {
    try {
      RenderRepaintBoundary boundary =
          globalKey.currentContext?.findRenderObject() as RenderRepaintBoundary;
      ui.Image image = await boundary.toImage(pixelRatio: 3.0);
      ByteData? byteData =
          await image.toByteData(format: ui.ImageByteFormat.png);
      return byteData?.buffer.asUint8List();
    } catch (e) {
      return null;
    }
  }

保存图片到本地 ​

使用 path_provider 插件访问设备的文件系统,并将图片保存到本地。首先在 pubspec.yaml 中添加依赖:

yaml
dependencies:
  path_provider: ^2.0.9
  image_gallery_saver: ^1.7.1
  permission_handler: ^10.2.0

接着,通过 path_provider 获取外部存储路径,并保存图片到该路径。

dart
Future<void> saveImageToLocal(Uint8List imageBytes) async {
  final directory = await getExternalStorageDirectory();
  final imagePath = '${directory!.path}/screenshot.png';
  File imgFile = File(imagePath);
  await imgFile.writeAsBytes(imageBytes);
  print('图片已保存至: $imagePath');
}

或者使用 ImageGallerySaver 保存到图库,同时需要注意存储图片时权限问题

Android: 在 AndroidManifest.xml 中添加存储权限:

dart
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>

iOS: 在 Info.plist 中添加图库权限描述:

dart
<key>NSPhotoLibraryAddUsageDescription</key>
<string>需要访问您的相册以保存图片。</string>
dart
class ImageGallerySaver {
  ...
  static FutureOr<dynamic> saveImage(Uint8List imageBytes,
      {int quality = 80,
      String? name,
      bool isReturnImagePathOfIOS = false}) async {
    final result =
        await _channel.invokeMethod('saveImageToGallery', <String, dynamic>{
      'imageBytes': imageBytes,
      'quality': quality,
      'name': name,
      'isReturnImagePathOfIOS': isReturnImagePathOfIOS
    });
    return result;
  }
  ...
}

/// 保存图片
  Future<dynamic> saveImage(Uint8List imageBytes) async {
    final result = await ImageGallerySaver.saveImage(imageBytes);
    return result;
  }